﻿using System;
using System.Collections.Generic;
using System.Drawing;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using System.Web.UI.DataVisualization.Charting;
using TestOnlineProject.Common;
using TestOnlineProject.Models.Entities;
using TestOnlineProject.Models.BusinessLogic;
using PagedList;
using System.IO;
using System.Globalization;

namespace TestOnlineProject.Controllers
{
    [Authorize]
    public class QuestionController : Controller
    {
        QuestionBLO questionBLO = new QuestionBLO();
        QuestionTypeBLO questionTypeBLO = new QuestionTypeBLO();
        SubjectBLO subjectBLO = new SubjectBLO();
        SectionBLO sectionBLO = new SectionBLO();
        UserBLO userBLO = new UserBLO();
        ParticipantBLO participantBLO = new ParticipantBLO();

        //
        // GET: /Admin/Question/

        public ActionResult Index(int? page, string keyWord = "", int questionTypeId = 0, string createdBy = "", int actualUser = 0, int subjectId = 0, int sectionId = 0, string column = "", string sort = "")
        {
            try
            {
                var subject = subjectBLO.Find(subjectId);
                var user = userBLO.Find(int.Parse(HttpContext.User.Identity.Name));
                // Check valid user
                if (user == null)
                {
                    return RedirectToAction("Error", "Account");
                }
                if (!user.IsActivated)
                {
                    return RedirectToAction("Error", "Account");
                }
                // Authorize.
                if (subject == null)
                {
                    return HttpNotFound();
                }
                if (sectionId > 0)
                {
                    var section = sectionBLO.Find(sectionId);
                    if(section == null)
                    {
                        return HttpNotFound();
                    }
                }
                if (!HttpContext.User.IsInRole("1"))
                {
                    if (sectionId > 0)
                    {
                        var section = sectionBLO.Find(sectionId);
                        if (!section.IsActivated)
                        {
                            TempData["Msg"] = "You can not access this section. Please contact Admin to more details.";
                            return RedirectToAction("Index", "Section", new { subjectId = section.SubjectId });
                        }
                    }
                    if (!participantBLO.CheckParticipant(int.Parse(HttpContext.User.Identity.Name), subjectId))
                    {
                        TempData["Msg"] = "You can not access this subject. Please contact Admin to more details.";
                        return RedirectToAction("Index", "Subject");
                    }
                }

                // No. list.
                var noList = new List<NoModel>();

                //User list.
                var questions = questionBLO.ToList(ref noList, page, keyWord, questionTypeId, createdBy, actualUser, subjectId, sectionId, column, sort);

                // Sort states.
                ViewBag.Msg = TempData["Msg"] as string;
                ViewBag.Page = page;
                ViewBag.KeyWord = keyWord;
                ViewBag.Column = column;
                ViewBag.Sort = sort;
                ViewBag.CreatedBy = createdBy;
                ViewBag.ActualUser = actualUser;
                ViewBag.NoList = noList;
                ViewBag.QuestionTypeId = questionTypeId;
                ViewBag.Subject = subject;
                ViewBag.SectionId = sectionId;

                var sections = sectionBLO.ToList(subjectId, int.Parse(HttpContext.User.Identity.Name));
                ViewBag.SectionList = sections;

                var createdBys = new List<CreatedByModel>
                    {
                        new CreatedByModel { Value = "mine", Text = "Mine" },
                        new CreatedByModel { Value = "admin", Text = "Admin" },
                        new CreatedByModel { Value = "teachers", Text = "Teachers" },
                        new CreatedByModel { Value = "students", Text = "Students" },
                        new CreatedByModel { Value = "actualUser", Text = "Actual People" }
                    };
                ViewBag.CreatedByList = new SelectList(createdBys, "Value", "Text");

                var actualUserList = userBLO.ToList().OrderBy(u => u.FullName).Select(u => new { Value = u.UserId, Text = u.FullName + " - " + u.Username });
                ViewBag.ActualUserList = new SelectList(actualUserList, "Value", "Text");

                var questionTypes = questionTypeBLO.ToList();
                ViewBag.QuestionTypeList = new SelectList(questionTypes, "QuestionTypeId", "Name");

                if (sectionId > 0)
                {
                    var section = sectionBLO.Find(sectionId);
                    ViewBag.Section = section;
                }

                var pageNumber = page ?? 1;
                var onePageOfQuestions = questions.ToPagedList(pageNumber, 10);
                ViewBag.onePageOfQuestions = onePageOfQuestions;

                // Return.
                return Request.IsAjaxRequest() ? (ActionResult)PartialView("_List") : View();
            }
            catch (Exception)
            {
                // Wrtite to log file.
                return RedirectToAction("Index", "Error", new { Area = "" });
            }
        }

        //
        // GET: /Question/AutocompleteUser

        public JsonResult AutocompleteUser(string term)
        {
            try
            {
                var users = userBLO.ToList();
                var result = users.Where(u => (u.FullName.ToLower().Contains(term.ToLower()))
                    || (u.Username.ToLower().Contains(term.ToLower()))).Select(u => new { id = u.UserId, value = u.FullName + " - " + u.Username });
                return Json(result, JsonRequestBehavior.AllowGet);
            }
            catch (Exception)
            {
                // Write to log file.
                return null;
            }
        }

        //
        // GET: /Question/AutocompleteSection

        public JsonResult AutocompleteSection(string term, int subjectId = 0)
        {
            var result = sectionBLO.ToList(term, subjectId).Select(u => new { id = u.SectionId, value = u.Name + " - " + u.User.FullName + " [" + u.User.Username + "]" }).ToList();
            return Json(result, JsonRequestBehavior.AllowGet);
        }

        //
        // GET: /Admin/Question/Import

        public ActionResult Import(int id = 0, int sectionId = 0)
        {
            var subject = subjectBLO.Find(id);
            // Check valid user
            var user = userBLO.Find(int.Parse(HttpContext.User.Identity.Name));
            if (user == null)
            {
                return RedirectToAction("Error", "Account");
            }
            if (!user.IsActivated)
            {
                return RedirectToAction("Error", "Account");
            }
            // Check valid section
            if (sectionId > 0)
            {
                var section = sectionBLO.Find(sectionId);
                if (section == null)
                {
                    return HttpNotFound();
                }
                ViewBag.Section = section;
            }
            // Authorize.
            if (subject == null)
            {
                return HttpNotFound();
            }
            if (!HttpContext.User.IsInRole("1"))
            {
                if (sectionId > 0)
                {
                    var section = sectionBLO.Find(sectionId);
                    if (!section.IsActivated)
                    {
                        TempData["Msg"] = "You can not access this section. Please contact Admin to more details.";
                        return RedirectToAction("Index", "Section", new { subjectId = section.SubjectId });
                    }
                }
                if (!participantBLO.CheckParticipant(int.Parse(HttpContext.User.Identity.Name), id))
                {
                    TempData["Msg"] = "You can not access this subject. Please contact Admin to more details.";
                    return RedirectToAction("Index", "Subject");
                }
            }

            var sectionMine = sectionBLO.ToList(id);
            sectionMine.Insert(0, new Section
                {
                    Name = "Select",
                    SectionId = 0
                });
            ViewBag.SectionMineList = new SelectList(sectionMine, "SectionId", "Name");

            ViewBag.Subject = subject;
            Session["subjectID"] = id;
            return View();
        }

        //
        // POST: /Admin/Question/Import

        [HttpPost]
        public JsonResult Import(HttpPostedFileBase file)
        {
            try
            {
                var sectionId = 0;
                var fileUpload = Request.Files["FileUpload"];
                int subjectId = Int32.Parse(Session["subjectId"].ToString());
                var section = Request.Form["SectionId"];
                if (section != "")
                {
                    sectionId = int.Parse(section);
                }
                if (fileUpload != null && fileUpload.ContentLength > 0)
                {
                    string saveFile = "~/ResourceFiles/" + fileUpload.FileName;
                    fileUpload.SaveAs(Server.MapPath(saveFile));

                    Exception ex;
                    int userId;
                    Int32.TryParse(HttpContext.User.Identity.Name, out userId);
                    int successQuestion;
                    int dublicateQuestion;
                    if (questionBLO.ParseFile(Server.MapPath(saveFile), userId, subjectId, out successQuestion, out dublicateQuestion, out ex,
                                              sectionId))
                    {
                        return new JsonResult
                            {
                                Data = new
                                    {
                                        success = true,
                                        successQuestion,
                                        dublicateQuestion,
                                        error = ""
                                    }
                            };
                    }
                    return new JsonResult
                        {
                            Data = new
                                {
                                    success = false,
                                    successQuestion,
                                    dublicateQuestion,
                                    error = ex.Message
                                }
                        };
                }
            }
            catch (Exception ex)
            {
                // Write to log file.
                return new JsonResult
                    {
                        Data = new
                            {
                                success = false,
                                error = ex.Message
                            }
                    };

            }
            return new JsonResult
                {
                    Data = new
                        {
                            success = false,
                            error = "No Valid File"
                        }
                };
        }

        //
        // GET: Import result

        public ActionResult ImportResult(int sectionId = 0, int page = 1, int size = 10)
        {
            try
            {
                var subjectId = 0;
                if (Session["subjectID"] != null)
                {
                    if (!Int32.TryParse(Session["subjectID"].ToString(), out subjectId))
                    {
                        subjectId = 0;
                    }
                }

                // Check valid user
                var user = userBLO.Find(int.Parse(HttpContext.User.Identity.Name));
                if (user == null)
                {
                    return RedirectToAction("Error", "Account");
                }
                if (!user.IsActivated)
                {
                    return RedirectToAction("Error", "Account");
                }
                // Check valid section
                if (sectionId > 0)
                {
                    var section = sectionBLO.Find(sectionId);
                    if (section == null)
                    {
                        return HttpNotFound();
                    }
                    ViewBag.Section = section;
                }

                if (!HttpContext.User.IsInRole("1"))
                {
                    if (sectionId > 0)
                    {
                        var section = sectionBLO.Find(sectionId);
                        if (!section.IsActivated)
                        {
                            TempData["Msg"] = "You can not access this section. Please contact Admin to more details.";
                            return RedirectToAction("Index", "Section", new { subjectId = section.SubjectId });
                        }
                    }
                    if (!participantBLO.CheckParticipant(int.Parse(HttpContext.User.Identity.Name), subjectId))
                    {
                        TempData["Msg"] = "You can not access this subject. Please contact Admin to more details.";
                        return RedirectToAction("Index", "Subject");
                    }
                }
                

                var subject = subjectBLO.Find(subjectId);
                // Authorize.
                if (subject == null)
                {
                    return HttpNotFound();
                }
                ViewBag.Subject = subject;

                var sections = sectionBLO.ToList(subjectId, int.Parse(HttpContext.User.Identity.Name));
                ViewBag.SectionList = sections;

                int userId;
                Int32.TryParse(HttpContext.User.Identity.Name, out userId);
                List<Question> listImportedQuestion = questionBLO.ListImportedQuestion(subjectId, userId, page, size);
                var noList = new List<NoModel>();
                for (var i = 0; i < listImportedQuestion.Count; i++)
                {
                    noList.Add(new NoModel
                    {
                        Id = listImportedQuestion[i].QuestionId,
                        No = i + 1
                    });
                }

                ViewBag.NoList = noList;
                ViewBag.onePageOfQuestions = listImportedQuestion.ToPagedList(page, size);
                ViewBag.IsImportResultPage = true;
                Session["subjectID"] = subjectId;

                return Request.IsAjaxRequest()
                       ? (ActionResult)PartialView("_List")
                       : View();
            }
            catch (Exception)
            {
                // Wrtite to log file.
                return RedirectToAction("Index", "Error", new { Area = "" });
            }
        }

        //
        // GET: /Admin/Question/Deactivate/5

        public string Deactivate(string ids = "")
        {
            try
            {
                int result = questionBLO.Deactivate(ids);
                if (result > 0)
                {
                    return result + " question(s) has been deactivated.";
                }
                return "question(s) is already deactivated.";
            }
            catch (Exception)
            {
                // Write to log file.
                return "An error occurred.";
            }
        }

        //
        // GET: /Admin/Question/Activate/5

        public string Activate(string ids = "")
        {
            try
            {
                int result = questionBLO.Activate(ids);
                if (result > 0)
                {
                    return result + " question(s) has been activated.";
                }
                return "question(s) is already activated.";
            }
            catch (Exception)
            {
                // Write to log file.
                return "An error occurred.";
            }
        }

        public string Delete(string ids = "")
        {
            try
            {
                int result = questionBLO.Remove(ids);
                if (result > 0)
                {
                    return result + " question(s) has been deleted.";
                }
                if (result == -1)
                {
                    return "The question(s) is using.";
                }
                return "You can not delete question of another person";
            }
            catch (Exception)
            {
                // Write to log file.
                return "An error occurred.";
            }
        }

        //
        // Get: /Admin/Question/DownloadTemplate

        public ActionResult DownloadTemplate()
        {
            return new DownloadModel
            {
                VirtualPath = "~/ResourceFiles/Template/Template_ImportQuestion.txt",
                FileDownLoadName = "Template_ImportQuestion.txt"
            };
        }

        //
        // Get: /Admin/Question/DownloadGuide

        public ActionResult DownloadGuide()
        {
            return new DownloadModel
            {
                VirtualPath = "~/ResourceFiles/Template/Guide_ImportQuestion.doc",
                FileDownLoadName = "Guide_ImportQuestion.doc"
            };
        }

        /// <summary>
        /// Create new question.
        /// </summary>
        /// <param name="questionTypeId"></param>
        /// <param name="subjectId"></param>
        /// <param name="sectionId"></param>
        /// <returns></returns>

        public ActionResult Create(int questionTypeId = 0, int subjectId = 0, int sectionId = 0)
        {
            try
            {
                // Authorize.
                var subject = subjectBLO.Find(subjectId);
                if (subject == null)
                {
                    return HttpNotFound();
                }
                // Check valid user
                var user = userBLO.Find(int.Parse(HttpContext.User.Identity.Name));
                if (user == null)
                {
                    return RedirectToAction("Error", "Account");
                }
                if (!user.IsActivated)
                {
                    return RedirectToAction("Error", "Account");
                }
                // Check valid section
                if (sectionId > 0)
                {
                    var section = sectionBLO.Find(sectionId);
                    if (section == null)
                    {
                        return HttpNotFound();
                    }
                }
                if (!HttpContext.User.IsInRole("1"))
                {
                    if (sectionId > 0)
                    {
                        var section = sectionBLO.Find(sectionId);
                        if (!section.IsActivated)
                        {
                            TempData["Msg"] = "You can not access this section. Please contact Admin to more details.";
                            return RedirectToAction("Index", "Section", new { subjectId = section.SubjectId });
                        }
                    }
                    if (!participantBLO.CheckParticipant(int.Parse(HttpContext.User.Identity.Name), subjectId))
                    {
                        TempData["Msg"] = "You can not access this subject. Please contact Admin to more details.";
                        return RedirectToAction("Index","Subject");
                    }
                }
                ViewBag.Subject = subject;

                // Get list QuestionTypes
                var questionTypes = questionTypeBLO.ToList();
                ViewBag.QuestionTypeList = new SelectList(questionTypes, "QuestionTypeId", "Name", questionTypeId);

                // Set ViewBage to save state.
                ViewBag.QuestionType =
                    questionTypeBLO.ToList().Where(t => t.QuestionTypeId == questionTypeId).Select(t => t.Name).FirstOrDefault();

                // Create QuestionModel for view.
                var questionModel = new QuestionModel
                    {
                        QuestionTypeId = questionTypeId,
                        SubjectId = subjectId
                    };

                // If question Type is single choice or multiple choice.
                // Create AnswerModel List with 1 item.
                if (questionTypeId == 1 || questionTypeId == 2)
                {
                    var answerModelList = new List<AnswerModel>();
                    for (var i = 0; i < 4; i++)
                    {
                        answerModelList.Add(new AnswerModel());
                    }
                    questionModel.Answers = answerModelList;
                }

                // If question Type is matching.
                // Create AnswerModel List with 1 item, MatchModel List with 1 item.
                if (questionTypeId == 3)
                {
                    var answerModelList = new List<AnswerModel>();
                    for (var i = 0; i < 4; i++)
                    {
                        answerModelList.Add(new AnswerModel());
                    }
                    var matchModelList = new List<MatchModel>();
                    for (var i = 0; i < 4; i++)
                    {
                        matchModelList.Add(new MatchModel());
                    }
                    questionModel.Answers = answerModelList;
                }

                // If question Type is true/false.
                // Create AnswerModel List with 2 item.
                if (questionTypeId == 4)
                {
                    var answerModelList = new List<AnswerModel>
                        {
                            new AnswerModel { Content = "True" },
                            new AnswerModel { Content = "False" }
                        };
                    questionModel.Answers = answerModelList;
                }

                SetViewBags(questionModel);
                if (sectionId != 0)
                {
                    var section = sectionBLO.Find(sectionId);
                    ViewBag.Section = section;
                }

                return View(questionModel);
            }
            catch (Exception)
            {
                // Write to log file.
                return RedirectToAction("Index", "Error");
            }
        }

        /// <summary>
        /// [POST] Create new question
        /// </summary>
        /// <param name="questionModel"></param>
        /// <param name="submit"></param>
        /// <returns></returns>

        [HttpPost]
        public ActionResult Create(QuestionModel questionModel, string submit)
        {
            try
            {
                var section = Request.Form["section"];
                var idSection = 0;
                if (section != "")
                {
                    idSection = int.Parse(section);
                }

                switch (submit)
                {
                    // User click on "Create" button.
                    case "Create":
                        if (ModelState.IsValid)
                        {
                            // Modify question.
                            var result = questionBLO.Add(questionModel);

                            if (result == -2)
                            {
                                // Set error message.
                                ModelState.AddModelError("", "You must enter at least 2 answer.");
                                SetViewBags(questionModel);
                                return View(questionModel);
                            }
                            if (result == -3)
                            {
                                // Set error message.
                                ModelState.AddModelError("", "You must select a correct answer.");
                                SetViewBags(questionModel);
                                return View(questionModel);
                            }
                            if (result == -4)
                            {
                                // Set error message.
                                ModelState.AddModelError("", "The positive grades you have chosen do not add up to 100%.");
                                SetViewBags(questionModel);
                                return View(questionModel);
                            }
                            if (result == -5)
                            {
                                // Set error message.
                                ModelState.AddModelError("", "You must enter at least 3 matches.");
                                SetViewBags(questionModel);
                                return View(questionModel);
                            }
                            if (result == -6)
                            {
                                // Set error message.
                                ModelState.AddModelError("", "You only have 10 answers.");
                                SetViewBags(questionModel);
                                return View(questionModel);
                            }
                            // If modification successful.
                            if (result > 0)
                            {
                                TempData["Msg"] = "The question has been created.";
                                return RedirectToAction("Details", "Question", new { id = questionModel.QuestionId, sectionId = idSection });
                            }
                        }

                        // Set ViewBages.
                        SetViewBags(questionModel);

                        return View(questionModel);

                    // User click on "More Answer" button.
                    case "More Answer":

                        // Set ViewBages.
                        SetViewBags(questionModel);

                        // Add more answer.
                        questionModel.Answers.Add(new AnswerModel());

                        // If question type is matching,
                        // Add more match.
                        if (questionModel.QuestionTypeId == 3)
                        {
                            questionModel.Matchs.Add(new MatchModel());
                        }

                        ViewBag.Section = sectionBLO.Find(idSection);

                        return View(questionModel);

                    // User click on "Remove Last Answer" button.
                    case "Remove Last Answer":

                        // Set ViewBages.
                        SetViewBags(questionModel);

                        // Remove last answer.
                        if (questionModel.Answers.Count > 1)
                        {
                            questionModel.Answers.RemoveAt(questionModel.Answers.Count - 1);
                            // If question type is matching,
                            if (questionModel.QuestionTypeId == 3)
                            {
                                questionModel.Matchs.RemoveAt(questionModel.Answers.Count - 1);
                            }
                        }

                        ViewBag.Section = sectionBLO.Find(idSection);

                        return View(questionModel);

                    case "More Match":
                        // Set ViewBages.
                        SetViewBags(questionModel);

                        if (questionModel.InvalidMatchs == null)
                        {
                            questionModel.InvalidMatchs = new List<MatchModel>();
                        }
                        questionModel.InvalidMatchs.Add(new MatchModel());

                        ViewBag.Section = sectionBLO.Find(idSection);

                        return View(questionModel);

                    case "Remove Last Match":
                        // Set ViewBages.
                        SetViewBags(questionModel);

                        // Remove last invalid match.
                        if (questionModel.InvalidMatchs != null && questionModel.InvalidMatchs.Count > 0)
                        {
                            questionModel.InvalidMatchs.RemoveAt(questionModel.InvalidMatchs.Count - 1);
                        }

                        ViewBag.Section = sectionBLO.Find(idSection);

                        return View(questionModel);
                }

                // Set ViewBages to save states.
                SetViewBags(questionModel);

                return View(questionModel);
            }
            catch (Exception)
            {
                // write to log file.
                return RedirectToAction("Index", "Error", new { Area = "" });
            }
        }

        /// <summary>
        /// Set ViewBages for Create Action to save states.
        /// </summary>
        /// <param name="questionModel"></param>

        private void SetViewBags(QuestionModel questionModel)
        {
            try
            {
                var sectionMine = sectionBLO.ToList(questionModel.SubjectId);
                sectionMine.Insert(0, new Section
                    {
                        Name = "Select",
                        SectionId = 0
                    });
                ViewBag.SectionMineList = new SelectList(sectionMine, "SectionId", "Name");

                var questionTypes = questionTypeBLO.ToList();
                ViewBag.QuestionTypeList = new SelectList(questionTypes, "QuestionTypeId", "Name",
                                                          questionModel.QuestionTypeId);
                ViewBag.Subject = subjectBLO.Find(questionModel.SubjectId);

                foreach (var ans in questionModel.Answers)
                {
                    // Grade select list
                    var listGrade = new List<SelectListItem>();
                    for (var i = 1; i <= 10; i++)
                    {
                        listGrade.Add(new SelectListItem
                            {
                                Selected = false,
                                Text = ((double)100 / i).ToString("F2", CultureInfo.CurrentUICulture),
                                Value = ((double)100 / i).ToString("F2", CultureInfo.CurrentUICulture),

                            });
                    }

                    listGrade.Add(new SelectListItem
                        {
                            Selected = false,
                            Text = (0).ToString("F2", CultureInfo.CurrentUICulture),
                            Value = (0).ToString("F2", CultureInfo.CurrentUICulture)
                        });

                    for (var i = 10; i >= 1; i--)
                    {
                        listGrade.Add(new SelectListItem
                            {
                                Selected = false,
                                Text = ((double)-100 / i).ToString("F2", CultureInfo.CurrentUICulture),
                                Value = ((double)-100 / i).ToString("F2", CultureInfo.CurrentUICulture)
                            });

                    }


                    for (var i = 0; i < listGrade.Count(); i++)
                    {
                        if (listGrade[i].Value == ans.Grade.ToString("F2", CultureInfo.CurrentUICulture))
                        {
                            listGrade[i].Selected = true;
                        }
                        else
                        {
                            listGrade[i].Selected = false;
                        }
                    }
                    Session["AnswerList" + ans.AnswerId + ""] = listGrade;
                }
            }
            catch (Exception)
            {
                // Wrtite to log file.
                RedirectToAction("Index", "Error", new { Area = "" });
            }
        }

        /// <summary>
        /// View question Details.
        /// </summary>
        /// <param name="id"></param>
        /// <param name="sectionId"></param>
        /// <returns></returns>

        public ActionResult Details(int id = 0, int sectionId = 0)
        {
            try
            {
                var question = questionBLO.Find(id);
                // Authorize.
                if (question == null)
                {
                    return HttpNotFound();
                }
                // Check valid subject
                var subject = subjectBLO.Find(question.SubjectId);
                if (subject == null)
                {
                    return HttpNotFound();
                }
                // Check valid user
                var user = userBLO.Find(int.Parse(HttpContext.User.Identity.Name));
                if (user == null)
                {
                    return RedirectToAction("Error", "Account");
                }
                if (!user.IsActivated)
                {
                    return RedirectToAction("Error", "Account");
                }
                // Check valid section
                if (sectionId > 0)
                {
                    var section = sectionBLO.Find(sectionId);
                    if (section == null)
                    {
                        return HttpNotFound();
                    }
                }

                if (!HttpContext.User.IsInRole("1"))
                {
                    if (sectionId > 0)
                    {
                        var section = sectionBLO.Find(sectionId);
                        if (!section.IsActivated)
                        {
                            TempData["Msg"] = "You can not access this section. Please contact Admin to more details.";
                            return RedirectToAction("Index", "Section", new { subjectId = section.SubjectId });
                        }
                    }
                    if (!participantBLO.CheckParticipant(int.Parse(HttpContext.User.Identity.Name), question.SubjectId))
                    {
                        TempData["Msg"] = "You can not access this subject. Please contact Admin to more details.";
                        return RedirectToAction("Index", "Subject");
                    }

                    if (!question.IsActivated)
                    {
                        TempData["Msg"] = "You can not access this question. Please contact Admin to more details.";
                        return RedirectToAction("Index", new { sectionId = sectionId, subjectId = question.SubjectId });
                    }
                }

                if (sectionId > 0)
                {
                    var section = sectionBLO.Find(sectionId);
                    ViewBag.Section = section;
                }

                var sections = sectionBLO.ToList(question.SubjectId, int.Parse(HttpContext.User.Identity.Name));
                ViewBag.SectionList = sections;

                ViewBag.Msg = TempData["Msg"] as string;
                ViewBag.Subject = subjectBLO.Find(questionBLO.Find(id).SubjectId);
                return View(question);
            }
            catch (Exception)
            {
                // Wrtite to log file.
                return RedirectToAction("Index", "Error", new { Area = "" });
            }
        }

        /// <summary>
        /// Edit question.
        /// </summary>
        /// <param name="id"></param>
        /// <param name="sectionId"></param>
        /// <returns></returns>

        public ActionResult Edit(int id = 0, int sectionId = 0)
        {
            try
            {
                var question = questionBLO.Find(id);
                // check valid question
                if (question == null)
                {
                    return HttpNotFound();
                }
                // Check valid subject
                var subject = subjectBLO.Find(question.SubjectId);
                if (subject == null)
                {
                    return HttpNotFound();
                }
                // Check valid user
                var user = userBLO.Find(int.Parse(HttpContext.User.Identity.Name));
                if (user == null)
                {
                    return RedirectToAction("Error", "Account");
                }
                if (!user.IsActivated)
                {
                    return RedirectToAction("Error", "Account");
                }
                // Check valid section
                if (sectionId > 0)
                {
                    var section = sectionBLO.Find(sectionId);
                    if (section == null)
                    {
                        return HttpNotFound();
                    }
                }
                if (!HttpContext.User.IsInRole("1"))
                {
                    if (sectionId > 0)
                    {
                        var section = sectionBLO.Find(sectionId);
                        if (!section.IsActivated)
                        {
                            TempData["Msg"] = "You can not access this section. Please contact Admin to more details.";
                            return RedirectToAction("Index", "Section", new { subjectId = section.SubjectId });
                        }
                    }
                    if (question.UserId != int.Parse(HttpContext.User.Identity.Name))
                    {
                        return HttpNotFound();
                    }
                    if (!participantBLO.CheckParticipant(int.Parse(HttpContext.User.Identity.Name), question.SubjectId))
                    {
                        TempData["Msg"] = "You can not access this subject. Please contact Admin to more details.";
                        return RedirectToAction("Index", "Subject");
                    }

                    if (!question.IsActivated)
                    {
                        TempData["Msg"] = "You can not access this question. Please contact Admin to more details.";
                        return RedirectToAction("Index", new {sectionId = sectionId, subjectId = question.SubjectId});
                    }
                }

                if (questionBLO.CheckIsUsingQuestion(id))
                {
                    // Set error message.
                    TempData["Msg"] = "The question is using.";
                    return RedirectToAction("Details", new { id = id, sectionId });
                }

                if (sectionId > 0)
                {
                    var section = sectionBLO.Find(sectionId);
                    ViewBag.Section = section;
                }

                // Set ViewBage to save state.
                ViewBag.QuestionType = questionTypeBLO.ToList().Where(t => t.QuestionTypeId == question.QuestionTypeId).Select(t => t.Name).FirstOrDefault();
                ViewBag.Subject = subjectBLO.Find(question.SubjectId);

                var questionModel = questionBLO.ConvertQuestionToQuestionModel(id);
                SetViewBags(questionModel);
                return View(questionModel);
            }
            catch (Exception)
            {
                // Write to log file.
                return RedirectToAction("Index", "Error", new { Area = "" });
            }
        }

        [HttpPost]
        public ActionResult Edit(QuestionModel questionModel, string submit, int sectionId = 0)
        {
            try
            {
                if (sectionId > 0)
                {
                    var section = sectionBLO.Find(sectionId);
                    ViewBag.Section = section;
                }

                switch (submit)
                {
                    // User click on "Save" button.
                    case "Save":
                        if (ModelState.IsValid)
                        {
                            // Modify question.
                            var result = questionBLO.Modify(questionModel);

                            // If modification unsuccessful.
                            if (result == -1)
                            {
                                // Set error message.
                                TempData["Msg"] = "The question data is out of date. Update unsuccessful";
                                return RedirectToAction("Details", new { id = questionModel.QuestionId, sectionId });
                            }
                            if (result == -2)
                            {
                                // Set error message.
                                ModelState.AddModelError("", "You must enter at least 2 answer.");
                                SetViewBags(questionModel);
                                return View(questionModel);
                            }
                            if (result == -3)
                            {
                                // Set error message.
                                ModelState.AddModelError("", "You must select a correct answer.");
                                SetViewBags(questionModel);
                                return View(questionModel);
                            }
                            if (result == -4)
                            {
                                // Set error message.
                                ModelState.AddModelError("", "The positive grades you have chosen do not add up to 100%.");
                                SetViewBags(questionModel);
                                return View(questionModel);
                            }
                            if (result == -5)
                            {
                                // Set error message.
                                ModelState.AddModelError("", "You must enter at least 3 matches.");
                                SetViewBags(questionModel);
                                return View(questionModel);
                            }

                            // If modification successful.
                            if (result > 0)
                            {
                                TempData["Msg"] = "The question has been updated.";
                                return RedirectToAction("Details", "Question", new { id = questionModel.QuestionId, sectionId });
                            }
                        }

                        // Set ViewBages.
                        SetViewBags(questionModel);

                        return View(questionModel);

                    // User click on "More Answer" button.
                    case "More Answer":

                        // Set ViewBages.
                        SetViewBags(questionModel);

                        // Add more answer.
                        questionModel.Answers.Add(new AnswerModel());

                        // If question type is matching,
                        // Add more match.
                        if (questionModel.QuestionTypeId == 3)
                        {
                            questionModel.Matchs.Add(new MatchModel());
                        }

                        return View(questionModel);

                    // User click on "Remove Last Answer" button.
                    case "Remove Last Answer":

                        // Set ViewBages.
                        SetViewBags(questionModel);

                        // Remove last answer.
                        if (questionModel.Answers.Count > 1)
                        {
                            questionModel.Answers.RemoveAt(questionModel.Answers.Count - 1);
                            // If question type is matching,
                            if (questionModel.QuestionTypeId == 3)
                            {
                                questionModel.Matchs.RemoveAt(questionModel.Answers.Count - 1);
                            }
                        }

                        return View(questionModel);

                    case "More Match":
                        // Set ViewBages.
                        SetViewBags(questionModel);

                        if (questionModel.InvalidMatchs == null)
                        {
                            questionModel.InvalidMatchs = new List<MatchModel>();
                        }
                        questionModel.InvalidMatchs.Add(new MatchModel());

                        return View(questionModel);

                    case "Remove Last Match":
                        // Set ViewBages.
                        SetViewBags(questionModel);

                        // Remove last invalid match.
                        if (questionModel.InvalidMatchs != null && questionModel.InvalidMatchs.Count > 0)
                        {
                            questionModel.InvalidMatchs.RemoveAt(questionModel.InvalidMatchs.Count - 1);
                        }

                        return View(questionModel);
                }

                // Set ViewBages to save states.
                SetViewBags(questionModel);

                return View(questionModel);
            }
            catch (Exception)
            {
                // write to log file.
                return RedirectToAction("Index", "Error", new { Area = "" });
            }
        }

        public ActionResult ColumnChart(int questionId)
        {
            var question = questionBLO.Find(questionId);
            // Create column chart
            var tuple = questionBLO.GenerateColumnChart(questionId);
            if(tuple.Item1 == null)
            {
                return null;
            }
            var listYvalue = tuple.Item1;
            var yValue = new int[tuple.Item2];
            var xValue = new List<string>();
            if (tuple.Item2 != 0)
            {
                for (int i = 0; i < tuple.Item2; i++)
                {
                    xValue.Add("Answer" + (i + 1));
                }
                for (int i = 0; i < listYvalue.Count(); i++)
                {
                    yValue[i] = listYvalue[i];
                }
            }
            var helper = new ChartHelper();
            var chart = new Chart
                {
                    Width = 350,
                    Height = 200,
                    BackColor = Color.FromArgb(211, 223, 240),
                    BorderlineDashStyle = ChartDashStyle.Solid,
                    BackSecondaryColor = Color.White,
                    BackGradientStyle = GradientStyle.TopBottom,
                    BorderlineWidth = 1,
                    Palette = ChartColorPalette.BrightPastel,
                    BorderlineColor = Color.FromArgb(26, 59, 105),
                    RenderType = RenderType.BinaryStreaming,
                    BorderSkin = { SkinStyle = BorderSkinStyle.Emboss },
                    AntiAliasing = AntiAliasingStyles.All,
                    TextAntiAliasingQuality = TextAntiAliasingQuality.Normal
                };
            // Title/ series/ chartarea for other chart
            if (question.QuestionTypeId != 3)
            {
                chart.Titles.Add(helper.CreateTitle("QuestionColumnChart"));
                chart.Series.Add(helper.CreateSeries(yValue, "QuestionColumnChart", xValue));
                chart.ChartAreas.Add(helper.CreateChartArea("QuestionColumnChart"));
            }
            // Title/ series/ chartarea for stacked column chart
            else
            {
                var tupleStack = questionBLO.GenerateStakedColumnChart(questionId);
                if(tupleStack.Item1.Sum()==0)
                {
                    return null;
                }
                int numMatches = tupleStack.Item2;
                var listsum = new int[tuple.Item2];
                yValue = new int[tuple.Item2];
                int j = 0;
                // Count sum of users
                for (int i = 0; i < tupleStack.Item1.Count(); i++)
                {
                    // count match for each answer
                    if (i > 0 && i % numMatches == 0)
                    {
                        j++;
                    }
                    listsum[j] += tupleStack.Item1[i];
                }
                // Add value to Y column
                for (int k = 0; k < numMatches; k++)
                {
                    int temp = k;
                    for (int i = 0; i < tuple.Item2; i++)
                    {
                        if (listsum[i] != 0)
                        {
                            if (temp == 0)
                            {
                                yValue[i] = (int)Math.Round(((double)tupleStack.Item1[i * numMatches] * 100) / listsum[i], MidpointRounding.AwayFromZero);
                            }
                            else
                            {
                                if (temp > 0 && i > 0)
                                {
                                    // next value
                                    temp += numMatches;
                                }
                                yValue[i] = (int)Math.Round(((double)tupleStack.Item1[temp] * 100) / listsum[i], MidpointRounding.AwayFromZero);
                            }

                        }
                    }
                    chart.Series.Add(helper.CreateSeries(yValue, "QuestionStackedColumnChart", xValue));
                }

                // Set legend
                for (int i = 0; i < numMatches; i++)
                {
                    chart.Series[i].Name = "Match" + (i + 1);
                }
                chart.Titles.Add(helper.CreateTitle("QuestionStackedColumnChart"));
                chart.ChartAreas.Add(helper.CreateChartArea("QuestionStackedColumnChart"));
                chart.Legends.Add(helper.CreateLengend());
                chart.Width = 500;
                chart.Height = 500;
            }

            var ms = new MemoryStream();
            chart.SaveImage(ms);

            return File(ms.GetBuffer(), @"image/png");
        }

        public ActionResult PieChart(int questionId)
        {
            // Create Pie chart
            var tuplePie = questionBLO.GeneratePieChart(questionId);
            var yValue = new int[] { };
            var xValue = new List<string>();
            if (tuplePie.Item1 != 0 || tuplePie.Item2 != 0)
            {
                yValue = new int[2];
                var percentTrue = (int)Math.Round((double)tuplePie.Item1 * 100 / (tuplePie.Item1 + tuplePie.Item2), MidpointRounding.AwayFromZero);
                var percentFalse = 100 - percentTrue;
                yValue[0] = percentTrue;
                yValue[1] = percentFalse;
                xValue.Add("True");
                xValue.Add("False");
            }
            else if (tuplePie.Item3 != null)
            {
                var count = new List<int>();
                int sum = 0;
                var temps = tuplePie.Item3;

                // Count sum of user
                for (var i = 0; i < temps.Count(); i++)
                {
                    sum += temps[i];
                }
                if(sum == 0)
                {
                    return null;
                }
                if (sum > 0)
                {
                    // Get value with num of user >0
                    for (var i = 0; i < temps.Count(); i++)
                    {
                        temps[i] = (int)Math.Round(((double)temps[i] * 100) / sum, MidpointRounding.AwayFromZero);
                        if (temps[i] > 0)
                        {
                            count.Add(i);
                        }
                    }

                    // Add to yvalue
                    yValue = new int[count.Count()];
                    var j = 0;
                    for (var i = 0; i < temps.Count(); i++)
                    {
                        if (temps[i] > 0)
                        {
                            yValue[j] = temps[i];
                            j++;
                        }
                    }
                    for (int i = 0; i < count.Count(); i++)
                    {
                        xValue.Add(count[i] + " correct answer(s)");
                    }
                }
            }

            var helper = new ChartHelper();
            var chart = new Chart
                {
                    Width = 350,
                    Height = 200,
                    BackColor = Color.FromArgb(211, 223, 240),
                    BorderlineDashStyle = ChartDashStyle.Solid,
                    BackSecondaryColor = Color.White,
                    BackGradientStyle = GradientStyle.TopBottom,
                    BorderlineWidth = 1,
                    Palette = ChartColorPalette.BrightPastel,
                    BorderlineColor = Color.FromArgb(26, 59, 105),
                    RenderType = RenderType.BinaryStreaming,
                    BorderSkin = { SkinStyle = BorderSkinStyle.Emboss },
                    AntiAliasing = AntiAliasingStyles.All,
                    TextAntiAliasingQuality = TextAntiAliasingQuality.Normal
                };
            chart.Titles.Add(helper.CreateTitle("QuestionPieChart"));
            chart.Series.Add(helper.CreateSeries(yValue, "QuestionPieChart", xValue));
            chart.ChartAreas.Add(helper.CreateChartArea("QuestionPieChart"));
            chart.Legends.Add(helper.CreateLengend());

            var ms = new MemoryStream();
            chart.SaveImage(ms);

            return File(ms.GetBuffer(), @"image/png");
        }

    }
}
